package publisher;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import aimpublisher.AIMPublisher;

import com.google.gdata.client.GoogleService;
import com.google.gdata.data.Entry;
import com.google.gdata.data.Feed;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;

import configuration.EntryExists;
import configuration.NoEntryException;

// STATE_INITIAL = 0
// STATE_ACQUIRING = 1
// STATE_HASEMAIL = 2
// STATE_HASPASSWORD = 3
// STATE_HASCONTENT = 4
public class Blogger extends Publisher {
	GoogleService blogService = new GoogleService("blogger", "AIMPublisher");
	
	public Blogger() { 
	}

	public void revertState(final int state) {
		// Prevent stack overflows by removing any Configuration entries that
		// we should not have at this point.
		switch (state) {
		case 0:	// STATE_INITIAL
		case 1: // STATE_ACQUIRING
			// We should NOT have the e-mail address, the password, or the
			// content at this point.
			if (AIMPublisher.getConfiguration().isEntry("Blogger",
					this.getIdentity(), "email")) {
				try {
					AIMPublisher.getConfiguration().removeEntry("Blogger",
							this.getIdentity(), "email");
				} catch (final NoEntryException e) {
					// can't happen
				}
			}
			if (AIMPublisher.getConfiguration().isEntry("Blogger",
					this.getIdentity(), "password")) {
				try {
					AIMPublisher.getConfiguration().removeEntry("Blogger",
							this.getIdentity(), "password");
				} catch (final NoEntryException e) {
					// can't happen
				}
			}
			if (AIMPublisher.getConfiguration().isEntry("Blogger",
					this.getIdentity(), "content")) {
				try {
					AIMPublisher.getConfiguration().removeEntry("Blogger",
							this.getIdentity(), "content");
				} catch (final NoEntryException e) {
					// can't happen
				}
			}
			break;
		case 2: // STATE_HASEMAIL
			// We should have the e-mail address at this point; we should NOT
			// have the password or the content at this point.
			if (AIMPublisher.getConfiguration().isEntry("Blogger",
					this.getIdentity(), "password")) {
				try {
					AIMPublisher.getConfiguration().removeEntry("Blogger",
							this.getIdentity(), "password");
				} catch (final NoEntryException e) {
					// can't happen
				}
			}
			if (AIMPublisher.getConfiguration().isEntry("Blogger",
					this.getIdentity(), "content")) {
				try {
					AIMPublisher.getConfiguration().removeEntry("Blogger",
							this.getIdentity(), "password");
				} catch (final NoEntryException e) {
					// can't happen
				}
			}
			break;
		case 3: // STATE_HASPASSWORD
			// We should have the e-mail address and the password at this point;
			// we should NOT have the content at this point.
			if (AIMPublisher.getConfiguration().isEntry("Blogger",
					this.getIdentity(), "content")) {
				try {
					AIMPublisher.getConfiguration().removeEntry("Blogger",
							this.getIdentity(), "content");
				} catch (final NoEntryException e) {
					// can't happen
				}
			}
			break;
		}
	}

	@Override
	public String run(final String message) {
		String email = null;
		String password = null;
		String content = null;

		// Retrieve the e-mail address
		if (AIMPublisher.getConfiguration().isEntry("Blogger",
				this.getIdentity(), "email")) {
			try {
				email = AIMPublisher.getConfiguration().getEntry("Blogger",
						this.getIdentity(), "email");
			} catch (final NoEntryException e) {
				// can't happen
			}
		}

		// Retrieve the password
		if (AIMPublisher.getConfiguration().isEntry("Blogger",
				this.getIdentity(), "password")) {
			try {
				password = AIMPublisher.getConfiguration().getEntry("Blogger",
						this.getIdentity(), "password");
			} catch (final NoEntryException e) {
				// can't happen
			}
		}

		// Retrieve the content
		if (AIMPublisher.getConfiguration().isEntry("Blogger",
				this.getIdentity(), "content")) {
			try {
				content = AIMPublisher.getConfiguration().getEntry("Blogger",
						this.getIdentity(), "content");
			} catch (final NoEntryException e) {
				// can't happen
			}
		}

		final int oldState = this.getState();

		if (email == null) {
			this.setState(1); // STATE_ACQUIRING
		} else if (password == null) {
			this.setState(2); // STATE_HASEMAIL
		} else if (content == null) {
			this.setState(3); // STATE_HASPASSWORD
		} else {
			this.setState(4); // STATE_HASCONTENT
		}

		// STATE_INITIAL -> STATE_ACQUIRING
		if ((oldState == 0) && (this.getState() == 1)) {
			return "Please specify an e-mail address.";
		}

		// STATE_INITIAL -> STATE_HASEMAIL
		if ((oldState == 0) && (this.getState() == 2)) {
			return "Please specify a password.";
		}

		// STATE_INITIAL -> STATE_HASPASSWORD
		if ((oldState == 0) && (this.getState() == 3)) {
			return "Please specify a message.";
		}

		// STATE_INITIAL -> STATE_HASCONTENT
		if ((oldState == 0) && (this.getState() == 4)) {
			return "Please specify a title.";
		}

		switch (this.getState()) {
		case 1: // STATE_ACQUIRING
			// Store the e-mail address for later retrieval
			email = message;
			try {
				if (AIMPublisher.getConfiguration().isEntry("Blogger",
						this.getIdentity(), "email")) {
					AIMPublisher.getConfiguration().changeEntry("Blogger",
							this.getIdentity(), "email", email);
				} else {
					AIMPublisher.getConfiguration().addEntry("Blogger",
							this.getIdentity(), "email", email);
				}
			} catch (final EntryExists e) {
				// can't happen
			} catch (final NoEntryException e) {
				// can't happen
			}

			return "Please specify a password.";
		case 2: // STATE_HASEMAIL
			// Store the password for later retrieval
			password = message;
			try {
				if (AIMPublisher.getConfiguration().isEntry("Blogger",
						this.getIdentity(), "password")) {
					AIMPublisher.getConfiguration().changeEntry("Blogger",
							this.getIdentity(), "password", password);
				} else {
					AIMPublisher.getConfiguration().addEntry("Blogger",
							this.getIdentity(), "password", password);
				}
			} catch (final EntryExists e) {
				// can't happen
			} catch (final NoEntryException e) {
				// can't happen
			}
			
			try {
				blogService.setUserCredentials(email, password);
			} catch (final AuthenticationException e) {
				// Revert to STATE_ACQUIRING to acquire the e-mail address and
				// the password
				this.revertState(1);
				return "Please specify another e-mail address.";
			}

			return "Please specify a message.";
		case 3: // STATE_HASPASSWORD
			// Store the content for later retrieval
			content = message;
			try {
				if (AIMPublisher.getConfiguration().isEntry("Blogger",
						this.getIdentity(), "content")) {
					AIMPublisher.getConfiguration().changeEntry("Blogger",
							this.getIdentity(), "content", content);
				} else {
					AIMPublisher.getConfiguration().addEntry("Blogger",
							this.getIdentity(), "content", content);
				}
			} catch (final EntryExists e) {
				// can't happen
			} catch (final NoEntryException e) {
				// can't happen
			}

			return "Please specify a title.";
		case 4: // STATE_HASCONTENT
			try {
				blogService.setUserCredentials(email, password);
			} catch (final AuthenticationException e) {
				// Revert to STATE_ACQUIRING to acquire the e-mail address and
				// the password
				this.revertState(1);
				return "Please specify another e-mail address.";
			}
	
			final Entry theEntry = new Entry();
			theEntry.setTitle(new PlainTextConstruct(message));
			theEntry.setContent(new PlainTextConstruct(content));

			URL feedUrl = null;
			try {
				feedUrl = new URL("http://www.blogger.com/feeds/default/blogs");
			} catch (final MalformedURLException e) {
				// can't happen
			}

			Feed resultFeed;
			try {
				resultFeed = blogService.getFeed(feedUrl, Feed.class);
			} catch (final IOException e) {
				e.printStackTrace();
				return null;
			} catch (final ServiceException e) {
				e.printStackTrace();
				return null;
			}

			final Entry firstBlog = resultFeed.getEntries().get(0);
			final String[] splitSelfLink = firstBlog.getSelfLink().getHref()
					.split("/");
			final String blogID = splitSelfLink[splitSelfLink.length - 1];

			URL postUrl;
			try {
				postUrl = new URL("http://www.blogger.com/feeds/" + blogID
						+ "/posts/default");
			} catch (final MalformedURLException e) {
				e.printStackTrace();
				return null;
			}

			try {
				blogService.insert(postUrl, theEntry);
			} catch (final IOException e) {
				e.printStackTrace();
				return null;
			} catch (final ServiceException e) {
				e.printStackTrace();
				this.revertState(3); // STATE_HASPASSWORD
				return "Please specify another message.";
			}

			this.revertState(3); // STATE_HASPASSWORD
			this.setState(0); // STATE_INITIAL
			return "The message was published to "
					+ firstBlog.getTitle().getPlainText() + " successfully.";
		}

		return null;
	}
}